
#include "core/threads.h"
#include "core/config.h"
#include "core/pool.h"
#include "core/logs.h"

#include <windows.h>
#include <process.h>

/************************************************************************\
 * Thread                                                               *
\************************************************************************/

struct VEThread
{
	uintptr_t     handle;
	VEThreadFunc  func;
	void         *data;
};

VE_DEFINE_STATIC_POOL(VEThread,VE_MAX_THREAD_COUNT)

static unsigned int _stdcall ve_thread_func( void *data )
{
	VEThread *thread = (VEThread*)data;
	thread->func( thread->data );
	return 0;
}

VEThread * ve_thread_create( VEThreadFunc func, void *data )
{
	VEThread *thread = ve_pool_alloc_VEThread();
	if( !thread )
	{
		ve_log_fatal( "ve_thread_create: Failed to allocate thread" );
		return 0;
	}
	thread->func = func;
	thread->data = data;
	thread->handle = _beginthreadex( 0, 0, ve_thread_func, thread, 0, 0 );
	return thread;
}

void ve_thread_delete( VEThread *thread )
{
	WaitForSingleObject( (HANDLE)thread->handle, INFINITE );
	ve_pool_free_VEThread( thread );
}

/************************************************************************\
 * Mutex                                                               *
\************************************************************************/

struct VEMutex
{
	CRITICAL_SECTION cs;
};

VE_DEFINE_STATIC_POOL(VEMutex,VE_MAX_MUTEX_COUNT)

VEMutex * ve_mutex_create()
{
	VEMutex *mutex = ve_pool_alloc_VEMutex();
	if( !mutex )
	{
		ve_log_fatal( "ve_mutex_create: Failed to allocate mutex" );
		return 0;
	}
	InitializeCriticalSection( &mutex->cs );
	return mutex;
}

void ve_mutex_delete( VEMutex *mutex )
{
	DeleteCriticalSection( &mutex->cs );
	ve_pool_free_VEMutex( mutex );
}

void ve_mutex_lock( VEMutex *mutex )
{
	EnterCriticalSection( &mutex->cs );
}

void ve_mutex_unlock( VEMutex *mutex )
{
	LeaveCriticalSection( &mutex->cs );
}

/************************************************************************\
 * Thread event                                                         *
\************************************************************************/

struct VEThreadEvent
{
	HANDLE event;
};

VE_DEFINE_STATIC_POOL(VEThreadEvent,VE_MAX_THREAD_EVENT_COUNT)

VEThreadEvent * ve_thread_event_create()
{
	VEThreadEvent *event = ve_pool_alloc_VEThreadEvent();
	if( !event )
	{
		ve_log_fatal( "ve_thread_event_create: Failed to allocate thread event" );
		return 0;
	}
	event->event = CreateEvent( 0, 0, 0, 0 );
	return event;
}

void ve_thread_event_delete( VEThreadEvent *event )
{
	CloseHandle( event->event );
	ve_pool_free_VEThreadEvent( event );
}

void ve_thread_event_signal( VEThreadEvent *event )
{
	SetEvent( event->event );
}

void ve_thread_event_wait( VEThreadEvent *event )
{
	WaitForSingleObject( event->event, INFINITE );
}
